package org.jeecg.modules.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.entity.SysPermission;
import org.jeecg.modules.system.entity.SysPermissionDataRule;
import org.jeecg.modules.system.entity.SysRolePermission;
import org.jeecg.modules.system.mapper.SysDepartPermissionMapper;
import org.jeecg.modules.system.mapper.SysDepartRolePermissionMapper;
import org.jeecg.modules.system.mapper.SysPermissionMapper;
import org.jeecg.modules.system.mapper.SysRolePermissionMapper;
import org.jeecg.modules.system.mapper.SysUserRoleMapper;
import org.jeecg.modules.system.mapper.SysPermissionDataRuleMapper;
import org.jeecg.modules.system.model.TreeModel;
import org.jeecg.modules.system.service.ISysPermissionDataRuleService;
import org.jeecg.modules.system.service.ISysPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONArray;
import org.apache.commons.lang.StringUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单权限表 服务实现类
 * </p>
 *
 * @Author scott
 * @since 2018-12-21
 */
@Service
public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, SysPermission> implements ISysPermissionService {

	@Resource
	private SysPermissionMapper sysPermissionMapper;
	
	@Resource
	private ISysPermissionDataRuleService permissionDataRuleService;

	@Resource
	private SysRolePermissionMapper sysRolePermissionMapper;

	@Resource
	private SysDepartPermissionMapper sysDepartPermissionMapper;

	@Resource
	private SysDepartRolePermissionMapper sysDepartRolePermissionMapper;
	
	@Resource
	private SysUserRoleMapper sysUserRoleMapper;
	
	@Resource
	private SysPermissionDataRuleMapper sysPermissionDataRuleMapper;
	
	@Autowired
	private RedisUtil redisUtil;

	@Override
	public void switchVue3Menu() {
		sysPermissionMapper.backupVue2Menu();
		sysPermissionMapper.changeVue3Menu();
	}

	@Override
	public List<TreeModel> queryListByParentId(String parentId) {
		return sysPermissionMapper.queryListByParentId(parentId);
	}

	/**
	  * 真实删除
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	@CacheEvict(value = CacheConstant.SYS_DATA_PERMISSIONS_CACHE,allEntries=true)
	public void deletePermission(String id) throws JeecgBootException {
		SysPermission sysPermission = this.getById(id);
		if(sysPermission==null) {
			throw new JeecgBootException("未找到菜单信息");
		}
		String pid = sysPermission.getParentId();
		if(oConvertUtils.isNotEmpty(pid)) {
			Long count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, pid));
			if(count==1) {
				//若父节点无其他子节点，则该父节点是叶子节点
				this.sysPermissionMapper.setMenuLeaf(pid, 1);
			}
		}
		sysPermissionMapper.deleteById(id);
		// 该节点可能是子节点但也可能是其它节点的父节点,所以需要级联删除
		this.removeChildrenBy(sysPermission.getId());
		//关联删除
		Map map = new HashMap(5);
		map.put("permission_id",id);
		//删除数据规则
		this.deletePermRuleByPermId(id);
		//删除角色授权表
		sysRolePermissionMapper.deleteByMap(map);
		//删除部门权限表
		sysDepartPermissionMapper.deleteByMap(map);
		//删除部门角色授权
		sysDepartRolePermissionMapper.deleteByMap(map);
	}
	
	/**
	 * 根据父id删除其关联的子节点数据
	 * 
	 * @return
	 */
	public void removeChildrenBy(String parentId) {
		LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<>();
		// 封装查询条件parentId为主键,
		query.eq(SysPermission::getParentId, parentId);
		// 查出该主键下的所有子级
		List<SysPermission> permissionList = this.list(query);
		if (permissionList != null && permissionList.size() > 0) {
            // id
			String id = "";
            // 查出的子级数量
			Long num = Long.valueOf(0);
			// 如果查出的集合不为空, 则先删除所有
			this.remove(query);
			// 再遍历刚才查出的集合, 根据每个对象,查找其是否仍有子级
			for (int i = 0, len = permissionList.size(); i < len; i++) {
				id = permissionList.get(i).getId();
				Map map = new HashMap(5);
				map.put("permission_id",id);
				//删除数据规则
				this.deletePermRuleByPermId(id);
				//删除角色授权表
				sysRolePermissionMapper.deleteByMap(map);
				//删除部门权限表
				sysDepartPermissionMapper.deleteByMap(map);
				//删除部门角色授权
				sysDepartRolePermissionMapper.deleteByMap(map);
				num = this.count(new LambdaQueryWrapper<SysPermission>().eq(SysPermission::getParentId, id));
				// 如果有, 则递归
				if (num > 0) {
					this.removeChildrenBy(id);
				}
			}
		}
	}
	
	/**
	  * 逻辑删除
	 */
	@Override
	@CacheEvict(value = CacheConstant.SYS_DATA_PERMISSIONS_CACHE,allEntries=true)
	//@CacheEvict(value = CacheConstant.SYS_DATA_PERMISSIONS_CACHE,allEntries=true,condition="#sysPermission.menuType==2")
	public void deletePermissionLogical(String id) throws JeecgBootException {
		SysPermission sysPermission = this.getById(id);
		if(sysPermission==null) {
			throw new JeecgBootException("未找到菜单信息");
		}
		String pid = sysPermission.getParentId();
		Long count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, pid));
		if(count==1) {
			//若父节点无其他子节点，则该父节点是叶子节点
			this.sysPermissionMapper.setMenuLeaf(pid, 1);
		}
		sysPermission.setDelFlag(1);
		this.updateById(sysPermission);
	}

	@Override
	@CacheEvict(value = CacheConstant.SYS_DATA_PERMISSIONS_CACHE,allEntries=true)
	public void addPermission(SysPermission sysPermission) throws JeecgBootException {
		//----------------------------------------------------------------------
		//判断是否是一级菜单，是的话清空父菜单
		if(CommonConstant.MENU_TYPE_0.equals(sysPermission.getMenuType())) {
			sysPermission.setParentId(null);
		}
		//----------------------------------------------------------------------
		String pid = sysPermission.getParentId();
		if(oConvertUtils.isNotEmpty(pid)) {
			//设置父节点不为叶子节点
			this.sysPermissionMapper.setMenuLeaf(pid, 0);
		}
		sysPermission.setCreateTime(new Date());
		sysPermission.setDelFlag(0);
		sysPermission.setLeaf(true);
		this.save(sysPermission);
	}

	@Override
	@CacheEvict(value = CacheConstant.SYS_DATA_PERMISSIONS_CACHE,allEntries=true)
	public void editPermission(SysPermission sysPermission) throws JeecgBootException {
		SysPermission p = this.getById(sysPermission.getId());
		//TODO 该节点判断是否还有子节点
		if(p==null) {
			throw new JeecgBootException("未找到菜单信息");
		}else {
			sysPermission.setUpdateTime(new Date());
			//----------------------------------------------------------------------
			//Step1.判断是否是一级菜单，是的话清空父菜单ID
			if(CommonConstant.MENU_TYPE_0.equals(sysPermission.getMenuType())) {
				sysPermission.setParentId("");
			}
			//Step2.判断菜单下级是否有菜单，无则设置为叶子节点
			Long count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, sysPermission.getId()));
			if(count==0) {
				sysPermission.setLeaf(true);
			}
			//----------------------------------------------------------------------
			this.updateById(sysPermission);
			
			//如果当前菜单的父菜单变了，则需要修改新父菜单和老父菜单的，叶子节点状态
			String pid = sysPermission.getParentId();
            boolean flag = (oConvertUtils.isNotEmpty(pid) && !pid.equals(p.getParentId())) || oConvertUtils.isEmpty(pid)&&oConvertUtils.isNotEmpty(p.getParentId());
            if (flag) {
				//a.设置新的父菜单不为叶子节点
				this.sysPermissionMapper.setMenuLeaf(pid, 0);
				//b.判断老的菜单下是否还有其他子菜单，没有的话则设置为叶子节点
				Long cc = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, p.getParentId()));
				if(cc==0) {
					if(oConvertUtils.isNotEmpty(p.getParentId())) {
						this.sysPermissionMapper.setMenuLeaf(p.getParentId(), 1);
					}
				}
				
			}
		}
		
	}

	@Override
	public List<SysPermission> queryByUser(String username) {
		return this.sysPermissionMapper.queryByUser(username);
	}

	/**
	 * 根据permissionId删除其关联的SysPermissionDataRule表中的数据
	 */
	@Override
	public void deletePermRuleByPermId(String id) {
		LambdaQueryWrapper<SysPermissionDataRule> query = new LambdaQueryWrapper<>();
		query.eq(SysPermissionDataRule::getPermissionId, id);
		Long countValue = this.permissionDataRuleService.count(query);
		if(countValue > 0) {
			this.permissionDataRuleService.remove(query);	
		}
	}

	/**
	  *   获取模糊匹配规则的数据权限URL
	 */
	@Override
	@Cacheable(value = CacheConstant.SYS_DATA_PERMISSIONS_CACHE)
	public List<String> queryPermissionUrlWithStar() {
		return this.baseMapper.queryPermissionUrlWithStar();
	}

	@Override
	public boolean hasPermission(String username, SysPermission sysPermission) {
		int count = baseMapper.queryCountByUsername(username,sysPermission);
		if(count>0){
			return true;
		}else{
			return false;
		}
	}

	@Override
	public boolean hasPermission(String username, String url) {
		SysPermission sysPermission = new SysPermission();
		sysPermission.setUrl(url);
		int count = baseMapper.queryCountByUsername(username,sysPermission);
		if(count>0){
			return true;
		}else{
			return false;
		}
	}

	@Override
	public List<SysPermission> queryDepartPermissionList(String departId) {
		return sysPermissionMapper.queryDepartPermissionList(departId);
	}

	@Override
	public boolean checkPermDuplication(String id, String url,Boolean alwaysShow) {
		QueryWrapper<SysPermission> qw=new QueryWrapper();
		qw.lambda().eq(true, SysPermission::getUrl,url).ne(oConvertUtils.isNotEmpty(id), SysPermission::getId,id).eq(true, SysPermission::isAlwaysShow,alwaysShow);
		return count(qw)==0;
	}
	
	@Override
	public List<TreeModel> queryTreeList() {
		List<SysPermission> list = this.list(new LambdaQueryWrapper<SysPermission>()
				.eq(SysPermission::getDelFlag, CommonConstant.DEL_FLAG_0)
				.orderByAsc(SysPermission::getSortNo));
		List<TreeModel> treeList = new java.util.ArrayList<>();
		this.getTreeModelList(treeList, list, null);
		return treeList;
	}
	
	@Override
	public List<TreeModel> queryUserAssignableTreeList(String userId) {
		// 获取用户拥有的权限
		List<SysPermission> userPermissions = null;
		
		// 判断是否为超级管理员
		String adminId = "e9ca23d68d884d4ebb19d07889727dae";
		if (adminId.equals(userId)) {
			// 超级管理员可以看到所有菜单
			userPermissions = this.list(new LambdaQueryWrapper<SysPermission>()
					.eq(SysPermission::getDelFlag, CommonConstant.DEL_FLAG_0)
					.orderByAsc(SysPermission::getSortNo));
		} else {
			// 非超级管理员只能看到自己有权限的菜单
			// 查询用户关联的角色
			List<String> roleIds = sysUserRoleMapper.getRoleIdByUserId(userId);
			if (roleIds != null && roleIds.size() > 0) {
				// 根据角色查询权限
				List<SysPermissionDataRule> permissionRuleList = null;
				userPermissions = new ArrayList<>();
				
				for (String roleId : roleIds) {
					// 根据角色ID查询角色拥有的权限
					List<SysRolePermission> rolePermissions = sysRolePermissionMapper.selectList(
							new QueryWrapper<SysRolePermission>().eq("role_id", roleId));
					
					// 转换为权限ID
					if (rolePermissions != null && rolePermissions.size() > 0) {
						List<String> permissionIds = rolePermissions.stream()
								.map(SysRolePermission::getPermissionId)
								.collect(Collectors.toList());
						
						// 查询具体权限
						List<SysPermission> rolePermissionList = sysPermissionMapper.selectList(
								new QueryWrapper<SysPermission>()
										.in("id", permissionIds)
										.eq("del_flag", CommonConstant.DEL_FLAG_0)
										.orderByAsc("sort_no"));
						
						userPermissions.addAll(rolePermissionList);
					}
				}
				
				// 去重
				if (userPermissions.size() > 0) {
					userPermissions = userPermissions.stream().distinct().collect(Collectors.toList());
				}
			}
		}
		
		// 构建树形结构
		List<TreeModel> treeList = new ArrayList<>();
		if (userPermissions != null && userPermissions.size() > 0) {
			this.getTreeModelList(treeList, userPermissions, null);
		}
		
		return treeList;
	}
	
	/**
	 * 递归构建树形结构
	 */
	private void getTreeModelList(List<TreeModel> treeList, List<SysPermission> metaList, TreeModel temp) {
		for (SysPermission permission : metaList) {
			String tempPid = permission.getParentId();
			TreeModel tree = new TreeModel(permission);
			if (temp == null && oConvertUtils.isEmpty(tempPid)) {
				treeList.add(tree);
				if (!tree.getIsLeaf()) {
					getTreeModelList(treeList, metaList, tree);
				}
			} else if (temp != null && tempPid != null && tempPid.equals(temp.getKey())) {
				temp.getChildren().add(tree);
				if (!tree.getIsLeaf()) {
					getTreeModelList(treeList, metaList, tree);
				}
			}
		}
	}

	@Override
	public List<JSONObject> getEmployeePermissionByEmpId(String empId) {
		// 通过员工ID获取其角色对应的权限列表
		List<SysPermission> permissionList = queryByEmployeeId(empId);
		
		// 如果没有权限，返回空列表
		if (permissionList == null || permissionList.isEmpty()) {
			return new ArrayList<>();
		}
		
		// 构建菜单树结构
		List<JSONObject> menuList = new ArrayList<>();
		
		// 获取一级菜单（类型为0的菜单）
		List<SysPermission> rootPermissions = permissionList.stream()
				.filter(permission -> permission.getMenuType().equals(CommonConstant.MENU_TYPE_0) 
						&& permission.getDelFlag().equals(CommonConstant.DEL_FLAG_0))
				.collect(Collectors.toList());
		
		// 构建一级菜单
		for (SysPermission permission : rootPermissions) {
			JSONObject json = new JSONObject();
			json.put("id", permission.getId());
			json.put("name", permission.getName());
			json.put("path", permission.getUrl());
			json.put("component", permission.getComponent());
			json.put("redirect", permission.getRedirect());
			json.put("meta", getMetaJSONObject(permission));
			json.put("hidden", permission.isHidden());
			json.put("alwaysShow", permission.isAlwaysShow());
			json.put("internalOrExternal", permission.isInternalOrExternal());
			
			// 获取子菜单（类型为1的菜单）
			List<SysPermission> subPermissions = permissionList.stream()
					.filter(subPerm -> subPerm.getParentId().equals(permission.getId()) 
							&& subPerm.getDelFlag().equals(CommonConstant.DEL_FLAG_0)
							&& subPerm.getMenuType().equals(CommonConstant.MENU_TYPE_1))
					.collect(Collectors.toList());
			
			// 构建子菜单
			if (!subPermissions.isEmpty()) {
				JSONArray children = new JSONArray();
				for (SysPermission subPermission : subPermissions) {
					JSONObject subJson = new JSONObject();
					subJson.put("id", subPermission.getId());
					subJson.put("name", subPermission.getName());
					subJson.put("path", subPermission.getUrl());
					subJson.put("component", subPermission.getComponent());
					subJson.put("meta", getMetaJSONObject(subPermission));
					subJson.put("hidden", subPermission.isHidden());
					subJson.put("alwaysShow", subPermission.isAlwaysShow());
					subJson.put("internalOrExternal", subPermission.isInternalOrExternal());
					
					// 获取按钮权限（类型为2的菜单）
					List<SysPermission> buttonPermissions = permissionList.stream()
							.filter(btn -> btn.getParentId().equals(subPermission.getId()) 
									&& btn.getDelFlag().equals(CommonConstant.DEL_FLAG_0)
									&& btn.getMenuType().equals(CommonConstant.MENU_TYPE_2))
							.collect(Collectors.toList());
					
					// 构建按钮权限
					if (!buttonPermissions.isEmpty()) {
						JSONArray buttons = new JSONArray();
						for (SysPermission btn : buttonPermissions) {
							JSONObject btnJson = new JSONObject();
							btnJson.put("id", btn.getId());
							btnJson.put("name", btn.getName());
							btnJson.put("path", btn.getUrl());
							btnJson.put("component", btn.getComponent());
							btnJson.put("meta", getMetaJSONObject(btn));
							btnJson.put("hidden", btn.isHidden());
							buttons.add(btnJson);
						}
						subJson.put("buttons", buttons);
					}
					
					children.add(subJson);
				}
				json.put("children", children);
			}
			
			menuList.add(json);
		}
		
		return menuList;
	}

	/**
	 * 构建菜单的meta对象
	 */
	private JSONObject getMetaJSONObject(SysPermission permission) {
		JSONObject meta = new JSONObject();
		meta.put("title", permission.getName());
		meta.put("icon", permission.getIcon());
		meta.put("keepAlive", permission.isKeepAlive());
		meta.put("hidden", permission.isHidden());
		return meta;
	}

	@Override
	public List<JSONObject> getEmployeePermissionByToken(String token) {
		List<JSONObject> menuList = null;
		try {
			// 从Redis获取员工信息
			Object empInfoObj = redisUtil.get(CommonConstant.PREFIX_EMPLOYEE_INFO + token);
			if (empInfoObj == null) {
				return null;
			}
			
			String empInfoJson = empInfoObj.toString();
			if (StringUtils.isNotBlank(empInfoJson)) {
				JSONObject employeeInfo = JSONObject.parseObject(empInfoJson);
				if (employeeInfo != null) {
					String employeeId = employeeInfo.getString("id");
					if (StringUtils.isNotBlank(employeeId)) {
						// 获取员工的权限菜单
						List<SysPermission> metaList = queryByEmployeeId(employeeId);
						if (metaList != null && metaList.size() > 0) {
							// 构建前端菜单
							menuList = new ArrayList<JSONObject>();
							for (SysPermission permission : metaList) {
								if (permission.getMenuType() != null && permission.getMenuType() == 0) {
									JSONObject json = new JSONObject();
									json.put("id", permission.getId());
									json.put("name", permission.getName());
									json.put("path", permission.getUrl());
									json.put("component", permission.getComponent());
									
									// 添加meta对象
									JSONObject meta = new JSONObject();
									meta.put("title", permission.getName());
									meta.put("icon", permission.getIcon());
									meta.put("keepAlive", permission.isKeepAlive());
									meta.put("hidden", permission.isHidden());
									json.put("meta", meta);
									
									// 添加其他重要属性
									json.put("redirect", permission.getRedirect());
									json.put("hidden", permission.isHidden());
									json.put("route", permission.isRoute());
									json.put("icon", permission.getIcon());
									json.put("parentId", permission.getParentId());
									json.put("leaf", false);
									json.put("sortNo", permission.getSortNo());
									
									menuList.add(json);
								}
							}
							// 递归获取子菜单
							getEmployeeSubmenuByParentId(menuList, metaList);
						}
					}
				}
			}
		} catch (Exception e) {
			log.error("根据Token获取员工菜单权限出错", e);
		}
		return menuList;
	}
	
	/**
	 * 递归获取员工子菜单
	 * @param menuList
	 * @param metaList
	 */
	private void getEmployeeSubmenuByParentId(List<JSONObject> menuList, List<SysPermission> metaList) {
		for (JSONObject json : menuList) {
			String parentId = json.getString("id");
			List<JSONObject> childList = new ArrayList<JSONObject>();
			for (SysPermission permission : metaList) {
				if (permission.getMenuType() != null && permission.getMenuType() == 1
						&& parentId.equals(permission.getParentId())) {
					JSONObject childJson = new JSONObject();
					childJson.put("id", permission.getId());
					childJson.put("name", permission.getName());
					childJson.put("path", permission.getUrl());
					childJson.put("component", permission.getComponent());
					
					// 添加meta对象
					JSONObject meta = new JSONObject();
					meta.put("title", permission.getName());
					meta.put("icon", permission.getIcon());
					meta.put("keepAlive", permission.isKeepAlive());
					meta.put("hidden", permission.isHidden());
					childJson.put("meta", meta);
					
					// 添加其他重要属性
					childJson.put("redirect", permission.getRedirect());
					childJson.put("hidden", permission.isHidden());
					childJson.put("route", permission.isRoute());
					childJson.put("icon", permission.getIcon());
					childJson.put("parentId", permission.getParentId());
					childJson.put("leaf", true);
					childJson.put("sortNo", permission.getSortNo());
					
					childList.add(childJson);
				}
			}
			if (childList.size() > 0) {
				json.put("children", childList);
				json.put("leaf", false);
				// 递归获取子菜单的子菜单
				getEmployeeSubmenuByParentId(childList, metaList);
			}
		}
	}

	/**
	 * 根据员工ID查询其权限
	 * @param employeeId 员工ID
	 * @return 权限列表
	 */
	public List<SysPermission> queryByEmployeeId(String employeeId) {
		List<SysPermission> permissionList = null;
		
		// 查询员工关联的角色
		List<String> roleIds = sysUserRoleMapper.getRoleIdByUserId(employeeId);
		if (roleIds != null && roleIds.size() > 0) {
			// 根据角色查询权限
			List<SysPermissionDataRule> permissionRuleList = null;
			for (String roleId : roleIds) {
				// 根据角色ID查询角色拥有的权限
				List<SysRolePermission> rolePermissions = sysRolePermissionMapper.selectList(
						new QueryWrapper<SysRolePermission>().eq("role_id", roleId));
				
				// 转换为权限ID
				if (rolePermissions != null && rolePermissions.size() > 0) {
					List<String> permissionIds = rolePermissions.stream()
							.map(SysRolePermission::getPermissionId)
							.collect(Collectors.toList());
					
					// 查询具体权限
					if (permissionList == null) {
						permissionList = new ArrayList<>();
					}
					
					List<SysPermission> rolePermissionList = sysPermissionMapper.selectList(
							new QueryWrapper<SysPermission>()
									.in("id", permissionIds)
									.eq("del_flag", CommonConstant.DEL_FLAG_0)
									.orderByAsc("sort_no"));
					
					permissionList.addAll(rolePermissionList);
					
					// 数据权限规则
					if (permissionRuleList == null) {
						permissionRuleList = new ArrayList<>();
					}
					
					List<SysPermissionDataRule> rolePermissionRuleList = sysPermissionDataRuleMapper.selectList(
							new QueryWrapper<SysPermissionDataRule>()
									.in("permission_id", permissionIds)
									.eq("status", CommonConstant.STATUS_1));
					
					permissionRuleList.addAll(rolePermissionRuleList);
				}
			}
			
			// 去重
			if (permissionList != null && permissionList.size() > 0) {
				permissionList = permissionList.stream().distinct().collect(Collectors.toList());
			}
		}
		
		return permissionList;
	}

}
